/* * Copyright (c) 2013-2017 Chris Newland. * Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD * Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki */ package org.adoptopenjdk.jitwatch.ui.main; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_DOT; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_SPACE; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEFAULT_PACKAGE_NAME; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_CLOSE_PARENTHESES; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_EMPTY; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_NEWLINE; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_SLASH; import static org.adoptopenjdk.jitwatch.util.UserInterfaceUtil.FONT_MONOSPACE_FAMILY; import static org.adoptopenjdk.jitwatch.util.UserInterfaceUtil.FONT_MONOSPACE_SIZE; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.adoptopenjdk.jitwatch.chain.CompileChainWalker; import org.adoptopenjdk.jitwatch.chain.CompileNode; import org.adoptopenjdk.jitwatch.compilation.codecache.CodeCacheEventWalker; import org.adoptopenjdk.jitwatch.compilation.codecache.CodeCacheWalkerResult; import org.adoptopenjdk.jitwatch.core.ErrorLog; import org.adoptopenjdk.jitwatch.core.IJITListener; import org.adoptopenjdk.jitwatch.core.JITWatchConfig; import org.adoptopenjdk.jitwatch.core.JITWatchConstants; import org.adoptopenjdk.jitwatch.model.Compilation; import org.adoptopenjdk.jitwatch.model.IMetaMember; import org.adoptopenjdk.jitwatch.model.IReadOnlyJITDataModel; import org.adoptopenjdk.jitwatch.model.JITEvent; import org.adoptopenjdk.jitwatch.model.MetaClass; import org.adoptopenjdk.jitwatch.model.PackageManager; import org.adoptopenjdk.jitwatch.optimizedvcall.OptimizedVirtualCall; import org.adoptopenjdk.jitwatch.optimizedvcall.OptimizedVirtualCallFinder; import org.adoptopenjdk.jitwatch.optimizedvcall.OptimizedVirtualCallVisitable; import org.adoptopenjdk.jitwatch.parser.ILogParseErrorListener; import org.adoptopenjdk.jitwatch.parser.ILogParser; import org.adoptopenjdk.jitwatch.parser.ParserFactory; import org.adoptopenjdk.jitwatch.parser.hotspot.HotSpotLogParser; import org.adoptopenjdk.jitwatch.report.Report; import org.adoptopenjdk.jitwatch.report.comparator.ScoreComparator; import org.adoptopenjdk.jitwatch.report.escapeanalysis.eliminatedallocation.EliminatedAllocationWalker; import org.adoptopenjdk.jitwatch.report.escapeanalysis.lockelision.ElidedLocksWalker; import org.adoptopenjdk.jitwatch.report.inlining.InliningWalker; import org.adoptopenjdk.jitwatch.report.suggestion.SuggestionWalker; import org.adoptopenjdk.jitwatch.ui.Dialogs; import org.adoptopenjdk.jitwatch.ui.browser.BrowserStage; import org.adoptopenjdk.jitwatch.ui.codecache.CodeCacheLayoutStage; import org.adoptopenjdk.jitwatch.ui.compilechain.CompileChainStage; import org.adoptopenjdk.jitwatch.ui.graphing.CodeCacheStage; import org.adoptopenjdk.jitwatch.ui.graphing.HistoStage; import org.adoptopenjdk.jitwatch.ui.graphing.TimeLineStage; import org.adoptopenjdk.jitwatch.ui.optimizedvcall.OptimizedVirtualCallStage; import org.adoptopenjdk.jitwatch.ui.report.ReportStage; import org.adoptopenjdk.jitwatch.ui.report.ReportStageType; import org.adoptopenjdk.jitwatch.ui.sandbox.SandboxStage; import org.adoptopenjdk.jitwatch.ui.stage.IStageClosedListener; import org.adoptopenjdk.jitwatch.ui.stage.StageManager; import org.adoptopenjdk.jitwatch.ui.stats.StatsStage; import org.adoptopenjdk.jitwatch.ui.toplist.TopListStage; import org.adoptopenjdk.jitwatch.ui.triview.TriView; import org.adoptopenjdk.jitwatch.ui.viewer.JournalViewerStage; import org.adoptopenjdk.jitwatch.ui.viewer.TextViewerStage; import org.adoptopenjdk.jitwatch.util.OSUtil; import org.adoptopenjdk.jitwatch.util.UserInterfaceUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Application; import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; import javafx.geometry.Orientation; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.SplitPane; import javafx.scene.control.TableView; import javafx.scene.control.TextArea; import javafx.scene.control.TreeItem; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.text.Text; import javafx.stage.FileChooser; import javafx.stage.Stage; import javafx.stage.WindowEvent; import javafx.util.Duration; public class JITWatchUI extends Application implements IJITListener, ILogParseErrorListener, IStageClosedListener, IStageAccessProxy, IMemberSelectedListener { private static final Logger logger = LoggerFactory.getLogger(JITWatchUI.class); public static final int WINDOW_WIDTH = 1024; public static final int WINDOW_HEIGHT = 550; private static final String JAVA_VERSION_7 = "1.7"; public static final boolean IS_JAVA_FX2; private boolean selectedProgrammatically = false; static { String version = System.getProperty("java.version", JAVA_VERSION_7); if (version.contains(JAVA_VERSION_7)) { IS_JAVA_FX2 = true; if (OSUtil.getOperatingSystem() == OSUtil.OperatingSystem.MAC) { UserInterfaceUtil.initMacFonts(); } } else { IS_JAVA_FX2 = false; } } private Stage stage; private ILogParser logParser; private ClassTree classTree; private ClassMemberList classMemberList; private TableView<CompilationTableRow> compilationTable; private ObservableList<CompilationTableRow> compilationRowList; private TextArea textAreaLog; private File jitLogFile = null; private String lastVmCommand = null; private IMetaMember lastSelectedMember = null; private MetaClass lastSelectedClass = null; private boolean isReadingLogFile = false; private Label lblVmVersion; private Label lblTweakLog; private Button btnStart; private Button btnStop; private Button btnConfigure; private Button btnTimeLine; private Button btnStats; private Button btnReset; private Button btnHisto; private Button btnTopList; private Button btnErrorLog; private Button btnCodeCacheTimeline; private Button btnNMethods; private Button btnTriView; private Button btnReportSuggestions; private Button btnReportEliminatedAllocations; private Button btnReportElidedLocks; private Button btnOptimizedVirtualCalls; private Button btnSandbox; private Label lblHeap; private MainConfigStage configStage; private TimeLineStage timeLineStage; private StatsStage statsStage; private HistoStage histoStage; private TopListStage topListStage; private CodeCacheStage codeCacheTimelineStage; private CodeCacheLayoutStage codeCacheBlocksStage; private TriView triViewStage; private BrowserStage browserStage; private ReportStage reportStageSuggestions; private ReportStage reportStageElminatedAllocations; private ReportStage reportStageElidedLocks; private OptimizedVirtualCallStage ovcStage; private SandboxStage sandBoxStage; private NothingMountedStage nothingMountedStage; private IMetaMember selectedMember; private MetaClass selectedMetaClass; private List<Report> reportListSuggestions = new ArrayList<>(); private List<Report> reportListEliminatedAllocations = new ArrayList<>(); private List<Report> reportListElidedLocks = new ArrayList<>(); private CodeCacheWalkerResult codeCacheWalkerResult; private Runtime runtime = Runtime.getRuntime(); // synchronized as buffer is drained async on GUI thread private StringBuffer logBuffer = new StringBuffer(); private ErrorLog errorLog = new ErrorLog(); private int errorCount = 0; private boolean repaintTree = false; private boolean startDelayedByConfig = false; // Called by JFX public JITWatchUI() { logParser = ParserFactory.getParser(this); } public JITWatchUI(String[] args) { launch(args); } private void readLogFile() { Thread jwThread = new Thread(new Runnable() { @Override public void run() { try { logParser.processLogFile(jitLogFile, JITWatchUI.this); } catch (IOException ioe) { log("Exception during log processing: " + ioe.toString()); } } }); jwThread.start(); } @Override public void handleReadStart() { startDelayedByConfig = false; isReadingLogFile = true; clear(); Platform.runLater(new Runnable() { @Override public void run() { updateButtons(); } }); } private void clear() { lastVmCommand = logParser.getVMCommand(); lastSelectedMember = selectedMember; lastSelectedClass = selectedMetaClass; selectedMember = null; errorCount = 0; errorLog.clear(); reportListSuggestions.clear(); reportListEliminatedAllocations.clear(); reportListElidedLocks.clear(); Platform.runLater(new Runnable() { @Override public void run() { classMemberList.clear(); StageManager.clearReportStages(); codeCacheWalkerResult = null; if (triViewStage != null) { triViewStage.clear(); } classTree.handleConfigUpdate(getConfig()); updateButtons(); classTree.clear(); metaClassSelectedFromClassTree(null); textAreaLog.clear(); refreshOnce(); } }); } @Override public void handleReadComplete() { log("Finished reading log file."); isReadingLogFile = false; buildSuggestions(); buildEliminatedAllocationReport(); buildElidedLocksReport(); buildCodeCacheResult(); Platform.runLater(new Runnable() { @Override public void run() { updateButtons(); refreshOnce(); } }); logParser.discardParsedLogs(); } private void buildSuggestions() { log("Finding code suggestions."); SuggestionWalker walker = new SuggestionWalker(logParser.getModel()); reportListSuggestions = walker.getReports(new ScoreComparator()); log("Found " + reportListSuggestions.size() + " code suggestions."); } private void buildEliminatedAllocationReport() { log("Finding eliminated allocations"); EliminatedAllocationWalker walker = new EliminatedAllocationWalker(logParser.getModel()); reportListEliminatedAllocations = walker.getReports(new ScoreComparator()); log("Found " + reportListEliminatedAllocations.size() + " eliminated allocations."); } private void buildElidedLocksReport() { log("Finding elided locks"); ElidedLocksWalker walker = new ElidedLocksWalker(logParser.getModel()); reportListElidedLocks = walker.getReports(new ScoreComparator()); log("Found " + reportListElidedLocks.size() + " elided locks."); } private void buildCodeCacheResult() { CodeCacheEventWalker compilationWalker = new CodeCacheEventWalker(logParser.getModel()); compilationWalker.walkCompilations(); codeCacheWalkerResult = compilationWalker.getResult(); } public CodeCacheWalkerResult getCodeCacheWalkerResult() { return codeCacheWalkerResult; } @Override public void handleError(final String title, final String body) { logger.error(title); Platform.runLater(new Runnable() { @Override public void run() { Dialogs.showOKDialog(JITWatchUI.this.stage, title, body); } }); } private void stopParsing() { if (isReadingLogFile) { logParser.stopParsing(); isReadingLogFile = false; updateButtons(); if (jitLogFile != null) { log("Stopped parsing " + jitLogFile.getAbsolutePath()); } } } @Override public JITWatchConfig getConfig() { return logParser.getConfig(); } @Override public void start(final Stage stage) { StageManager.registerListener(this); this.stage = stage; stage.setOnCloseRequest(new EventHandler<WindowEvent>() { @Override public void handle(WindowEvent arg0) { StageManager.closeStage(stage); stopParsing(); } }); BorderPane borderPane = new BorderPane(); Scene scene = UserInterfaceUtil.getScene(borderPane, WINDOW_WIDTH, WINDOW_HEIGHT); Button btnChooseWatchFile = new Button("Open Log"); btnChooseWatchFile.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { stopParsing(); chooseJITLog(); } }); btnStart = new Button("Start"); btnStart.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { if (nothingMountedStage == null) { int classCount = getConfig().getConfiguredClassLocations().size(); int sourceCount = getConfig().getSourceLocations().size(); if (classCount == 0 && sourceCount == 0) { if (getConfig().isShowNothingMounted()) { nothingMountedStage = new NothingMountedStage(JITWatchUI.this, getConfig()); StageManager.addAndShow(JITWatchUI.this.stage, nothingMountedStage); startDelayedByConfig = true; } } } if (!startDelayedByConfig) { readLogFile(); } } }); btnStop = new Button("Stop"); btnStop.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { stopParsing(); } }); btnConfigure = new Button("Config"); btnConfigure.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { openConfigStage(); } }); btnTimeLine = new Button("Timeline"); btnTimeLine.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { timeLineStage = new TimeLineStage(JITWatchUI.this); StageManager.addAndShow(JITWatchUI.this.stage, timeLineStage); btnTimeLine.setDisable(true); } }); btnHisto = new Button("Histo"); btnHisto.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { histoStage = new HistoStage(JITWatchUI.this); StageManager.addAndShow(JITWatchUI.this.stage, histoStage); btnHisto.setDisable(true); } }); btnTopList = new Button("TopList"); btnTopList.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { topListStage = new TopListStage(JITWatchUI.this); StageManager.addAndShow(JITWatchUI.this.stage, topListStage); btnTopList.setDisable(true); } }); btnCodeCacheTimeline = new Button("Cache"); btnCodeCacheTimeline.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { codeCacheTimelineStage = new CodeCacheStage(JITWatchUI.this); StageManager.addAndShow(JITWatchUI.this.stage, codeCacheTimelineStage); btnCodeCacheTimeline.setDisable(true); } }); btnNMethods = new Button("NMethods"); btnNMethods.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { codeCacheBlocksStage = new CodeCacheLayoutStage(JITWatchUI.this); StageManager.addAndShow(JITWatchUI.this.stage, codeCacheBlocksStage); btnNMethods.setDisable(true); codeCacheBlocksStage.redraw(); } }); btnTriView = new Button("TriView"); btnTriView.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { if (selectedMember == null && selectedMetaClass != null) { selectedMember = selectedMetaClass.getFirstConstructor(); } openTriView(selectedMember, false); } }); btnReportSuggestions = new Button("Suggest"); btnReportSuggestions.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { reportStageSuggestions = new ReportStage(JITWatchUI.this, "JITWatch Code Suggestions", ReportStageType.SUGGESTION, reportListSuggestions); StageManager.addAndShow(JITWatchUI.this.stage, reportStageSuggestions); btnReportSuggestions.setDisable(true); } }); btnReportEliminatedAllocations = new Button("-Allocs"); btnReportEliminatedAllocations.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { reportStageElminatedAllocations = new ReportStage(JITWatchUI.this, "JITWatch Eliminated Allocation Report", ReportStageType.ELIMINATED_ALLOCATION, reportListEliminatedAllocations); StageManager.addAndShow(JITWatchUI.this.stage, reportStageElminatedAllocations); btnReportEliminatedAllocations.setDisable(true); } }); btnReportElidedLocks = new Button("-Locks"); btnReportElidedLocks.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { reportStageElidedLocks = new ReportStage(JITWatchUI.this, "JITWatch Elided Lock Report", ReportStageType.ELIDED_LOCK, reportListElidedLocks); StageManager.addAndShow(JITWatchUI.this.stage, reportStageElidedLocks); btnReportElidedLocks.setDisable(true); } }); btnOptimizedVirtualCalls = new Button("OVCs"); btnOptimizedVirtualCalls.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { OptimizedVirtualCallVisitable optimizedVCallVisitable = new OptimizedVirtualCallVisitable(); List<OptimizedVirtualCall> optimizedVirtualCalls = optimizedVCallVisitable .buildOptimizedCalleeReport(logParser.getModel(), getConfig().getAllClassLocations()); ovcStage = new OptimizedVirtualCallStage(JITWatchUI.this, optimizedVirtualCalls); StageManager.addAndShow(JITWatchUI.this.stage, ovcStage); btnOptimizedVirtualCalls.setDisable(true); } }); btnSandbox = new Button("Sandbox"); btnSandbox.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { openSandbox(); } }); btnErrorLog = new Button("Errors (0)"); btnErrorLog.setStyle("-fx-padding: 2 6;"); btnErrorLog.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { openTextViewer("Error Log", errorLog.toString(), false, false); } }); btnStats = new Button("Stats"); btnStats.setStyle("-fx-padding: 2 6;"); btnStats.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { statsStage = new StatsStage(JITWatchUI.this); StageManager.addAndShow(JITWatchUI.this.stage, statsStage); btnStats.setDisable(true); } }); btnReset = new Button("Reset"); btnReset.setStyle("-fx-padding: 2 6;"); btnReset.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent e) { logParser.reset(); clear(); } }); lblHeap = new Label(); lblVmVersion = new Label(); StringBuilder vmBuilder = new StringBuilder(); vmBuilder.append("VM is "); vmBuilder.append(Runtime.class.getPackage().getImplementationVendor()); vmBuilder.append(C_SPACE); vmBuilder.append(Runtime.class.getPackage().getImplementationVersion()); lblVmVersion.setText(vmBuilder.toString()); lblTweakLog = new Label(); int menuBarHeight = 40; int textAreaHeight = 100; int statusBarHeight = 25; HBox hboxTop = new HBox(); hboxTop.setPadding(new Insets(10)); hboxTop.setPrefHeight(menuBarHeight); hboxTop.setSpacing(10); hboxTop.getChildren().add(btnSandbox); hboxTop.getChildren().add(btnChooseWatchFile); hboxTop.getChildren().add(btnStart); hboxTop.getChildren().add(btnStop); hboxTop.getChildren().add(btnConfigure); hboxTop.getChildren().add(btnTimeLine); hboxTop.getChildren().add(btnHisto); hboxTop.getChildren().add(btnTopList); hboxTop.getChildren().add(btnCodeCacheTimeline); hboxTop.getChildren().add(btnNMethods); hboxTop.getChildren().add(btnTriView); hboxTop.getChildren().add(btnReportSuggestions); hboxTop.getChildren().add(btnReportEliminatedAllocations); hboxTop.getChildren().add(btnReportElidedLocks); hboxTop.getChildren().add(btnOptimizedVirtualCalls); compilationRowList = FXCollections.observableArrayList(); compilationTable = CompilationTableBuilder.buildTableMemberAttributes(compilationRowList); compilationTable.setPlaceholder(new Text("Select a JIT-compiled class member to view compilations.")); compilationTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<CompilationTableRow>() { @Override public void changed(ObservableValue<? extends CompilationTableRow> arg0, CompilationTableRow oldVal, CompilationTableRow newVal) { if (!selectedProgrammatically) { if (selectedMember != null && newVal != null) { selectedMember.setSelectedCompilation(newVal.getIndex()); openTriView(selectedMember, true); refreshOnce(); } } } }); SplitPane spMethodInfo = new SplitPane(); spMethodInfo.setOrientation(Orientation.VERTICAL); classMemberList = new ClassMemberList(this, getConfig()); classMemberList.registerListener(this); spMethodInfo.getItems().add(classMemberList); spMethodInfo.getItems().add(compilationTable); classMemberList.prefHeightProperty().bind(scene.heightProperty()); compilationTable.prefHeightProperty().bind(scene.heightProperty()); classTree = new ClassTree(this, getConfig()); classTree.prefWidthProperty().bind(scene.widthProperty()); SplitPane spMain = new SplitPane(); spMain.setOrientation(Orientation.VERTICAL); SplitPane spCentre = new SplitPane(); spCentre.getItems().add(classTree); spCentre.getItems().add(spMethodInfo); spCentre.setDividerPositions(0.33, 0.67); textAreaLog = new TextArea(); textAreaLog.setStyle("-fx-font-family:" + FONT_MONOSPACE_FAMILY + ";-fx-font-size:" + FONT_MONOSPACE_SIZE + "px"); textAreaLog.setPrefHeight(textAreaHeight); log("Welcome to JITWatch by Chris Newland (@chriswhocodes on Twitter) and the AdoptOpenJDK project.\n"); log("Please send feedback to our mailing list (https://groups.google.com/forum/#!forum/jitwatch) \nor come and find us on GitHub (https://github.com/AdoptOpenJDK/jitwatch).\n"); log("Includes assembly reference from x86asm.net licenced under http://ref.x86asm.net/index.html#License\n"); if (jitLogFile == null) { if (logParser instanceof HotSpotLogParser) { log("HotSpot mode. Choose a JIT log file or open the Sandbox"); } else { log("J9 Mode. Choose a JIT log file (Sandbox only available for HotSpot)"); } } else { log("Using JIT log file: " + jitLogFile.getAbsolutePath()); } spMain.getItems().add(spCentre); spMain.getItems().add(textAreaLog); spMain.setDividerPositions(0.68, 0.32); HBox hboxBottom = new HBox(); Region springLeft = new Region(); Region springRight = new Region(); final String labelStyle = "-fx-padding: 3 0 0 0;"; HBox.setHgrow(springLeft, Priority.ALWAYS); HBox.setHgrow(springRight, Priority.ALWAYS); lblHeap.setStyle(labelStyle); lblVmVersion.setStyle(labelStyle); hboxBottom.setPadding(new Insets(4)); hboxBottom.setPrefHeight(statusBarHeight); hboxBottom.setSpacing(4); hboxBottom.getChildren().add(lblHeap); hboxBottom.getChildren().add(btnErrorLog); hboxBottom.getChildren().add(btnStats); hboxBottom.getChildren().add(btnReset); hboxBottom.getChildren().add(springLeft); hboxBottom.getChildren().add(lblTweakLog); hboxBottom.getChildren().add(springRight); hboxBottom.getChildren().add(lblVmVersion); borderPane.setTop(hboxTop); borderPane.setCenter(spMain); borderPane.setBottom(hboxBottom); stage.setTitle("JITWatch - Just In Time Compilation Inspector"); stage.setScene(scene); stage.show(); int refreshMillis = 1000; final Duration oneFrameAmt = Duration.millis(refreshMillis); final KeyFrame oneFrame = new KeyFrame(oneFrameAmt, new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent arg0) { refresh(); } }); Timeline timeline = new Timeline(); timeline.setCycleCount(Animation.INDEFINITE); timeline.getKeyFrames().add(oneFrame); timeline.play(); updateButtons(); } void openConfigStage() { if (configStage == null) { configStage = new MainConfigStage(this, this, getConfig()); StageManager.addAndShow(this.stage, configStage); btnConfigure.setDisable(true); } } @Override public void openTriView(IMetaMember member, boolean force) { openTriView(member, force, 0); } @Override public void openTriView(IMetaMember member, boolean force, int highlightBCI) { if (triViewStage == null) { triViewStage = new TriView(JITWatchUI.this, getConfig()); StageManager.addAndShow(this.stage, triViewStage); btnTriView.setDisable(true); } if (member != null) { triViewStage.setMember(member, force, highlightBCI); } } public void openSandbox() { if (sandBoxStage == null) { sandBoxStage = new SandboxStage(this, this, logParser); StageManager.addAndShow(this.stage, sandBoxStage); btnSandbox.setDisable(true); } } @Override public void openBrowser(String title, String html, String stylesheet) { if (browserStage == null) { browserStage = new BrowserStage(); StageManager.addAndShow(this.stage, browserStage); } browserStage.setContent(title, html, stylesheet); } public IReadOnlyJITDataModel getJITDataModel() { return logParser.getModel(); } private void updateButtons() { if (!(logParser instanceof HotSpotLogParser)) { btnSandbox.setDisable(true); } btnStart.setDisable(jitLogFile == null || isReadingLogFile); btnStop.setDisable(!isReadingLogFile); btnReportSuggestions.setText("Suggestions (" + reportListSuggestions.size() + S_CLOSE_PARENTHESES); btnReportEliminatedAllocations.setText("-Allocs (" + reportListEliminatedAllocations.size() + S_CLOSE_PARENTHESES); btnReportElidedLocks.setText("-Locks (" + reportListElidedLocks.size() + S_CLOSE_PARENTHESES); } public boolean focusTreeOnClass(MetaClass metaClass) { List<String> path = metaClass.getTreePath(); clearAndRefreshTreeView(); TreeItem<Object> curNode = classTree.getRootItem(); StringBuilder builtPath = new StringBuilder(); int pathLength = path.size(); int pos = 0; int rowsAbove = 0; boolean found = false; for (String part : path) { builtPath.append(part); String matching; found = false; if (pos++ == pathLength - 1) { matching = part; } else { matching = builtPath.toString(); } for (TreeItem<Object> node : curNode.getChildren()) { rowsAbove++; String nodeText = node.getValue().toString(); if (matching.equals(nodeText) || (S_EMPTY.equals(matching) && DEFAULT_PACKAGE_NAME.equals(nodeText))) { builtPath.append(C_DOT); curNode = node; curNode.setExpanded(true); classTree.select(curNode); found = true; break; } } } if (found) { classTree.scrollTo(rowsAbove); lastSelectedClass = null; } return found; } public void focusTreeOnMember(IMetaMember member, boolean openTriView) { if (member != null) { MetaClass metaClass = member.getMetaClass(); boolean found = focusTreeOnClass(metaClass); if (found) { classMemberList.selectMember(member); setSelectedMetaMember(member, openTriView); lastSelectedMember = null; } } } @Override public void openTextViewer(String title, String content, boolean lineNumbers, boolean highlighting) { TextViewerStage tvs = new TextViewerStage(this, title, content, lineNumbers, highlighting); StageManager.addAndShow(this.stage, tvs); } public void openTextViewer(String title, String content) { openTextViewer(title, content, false, false); } @Override public void openCompileChain(IMetaMember member) { if (member != null && member.isCompiled()) { CompileChainWalker walker = new CompileChainWalker(logParser.getModel()); CompileNode root = walker.buildCallTree(member.getSelectedCompilation()); if (root != null) { CompileChainStage ccs = new CompileChainStage(this, root); StageManager.addAndShow(this.stage, ccs); } else { logger.error("Could not open CompileChain - root node was null"); } } } @Override public void openOptmizedVCallReport(IMetaMember member) { if (member.isCompiled()) { OptimizedVirtualCallFinder finder = new OptimizedVirtualCallFinder(logParser.getModel(), getConfig().getAllClassLocations()); List<OptimizedVirtualCall> optimizedVirtualCalls = finder.findOptimizedCalls(member); OptimizedVirtualCallStage ovcs = new OptimizedVirtualCallStage(this, optimizedVirtualCalls); StageManager.addAndShow(this.stage, ovcs); } } @Override public void openInlinedIntoReport(IMetaMember member) { if (member != null) { log("Finding inlined into reports for " + member.toStringUnqualifiedMethodName(true, true)); InliningWalker walker = new InliningWalker(logParser.getModel(), member); List<Report> inlinedIntoMemberList = walker.getReports(new ScoreComparator()); log("Found " + inlinedIntoMemberList.size() + " locations."); ReportStage inlinedIntoStage = new ReportStage(JITWatchUI.this, "Inlining report for callee " + member.toStringUnqualifiedMethodName(true, true), ReportStageType.INLINING, inlinedIntoMemberList); StageManager.addAndShow(JITWatchUI.this.stage, inlinedIntoStage); } } public void openJournalViewer(String title, IMetaMember member) { if (member.isCompiled()) { JournalViewerStage jvs = new JournalViewerStage(this, title, member.getSelectedCompilation()); StageManager.addAndShow(this.stage, jvs); } } private void chooseJITLog() { FileChooser fc = new FileChooser(); fc.setTitle("Choose JIT log file"); String osNameProperty = System.getProperty("os.name"); // don't use ExtensionFilter on OSX due to JavaFX2 missing combo bug if (osNameProperty != null && !osNameProperty.toLowerCase().contains("mac")) { fc.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Log Files", "*.log"), new FileChooser.ExtensionFilter("All Files", "*.*")); } String searchDir = getConfig().getLastLogDir(); if (searchDir == null) { searchDir = System.getProperty("user.dir"); } File dirFile = new File(searchDir); if (!dirFile.exists() || !dirFile.isDirectory()) { dirFile = new File(System.getProperty("user.dir")); } fc.setInitialDirectory(dirFile); File result = fc.showOpenDialog(stage); if (result != null) { setJITLogFile(result); JITWatchConfig config = getConfig(); if (JITWatchConstants.S_PROFILE_SANDBOX.equals(config.getProfileName())) { logParser.getConfig().switchFromSandbox(); } } } // Call from UI thread private void setJITLogFile(File logFile) { jitLogFile = logFile; getConfig().setLastLogDir(jitLogFile.getParent()); getConfig().saveConfig(); clearTextArea(); log("Selected log file: " + jitLogFile.getAbsolutePath()); log("\nUsing Config: " + getConfig().getProfileName()); log("\nClick Start button to process the JIT log"); updateButtons(); refreshLog(); } private boolean sameVmCommand() { boolean same = false; if (lastVmCommand != null && logParser.getVMCommand() != null) { same = lastVmCommand.equals(logParser.getVMCommand()); if (!same) { // vm command known and not same so flush open node history classTree.clearOpenPackageHistory(); lastVmCommand = null; } } return same; } @Override public void setSelectedMetaMember(IMetaMember member, boolean openTriView) { compilationRowList.clear(); if (member == null) { return; } if (openTriView && triViewStage != null) { triViewStage.setMember(member, false); } selectedMember = member; for (Compilation compilation : member.getCompilations()) { CompilationTableRow row = new CompilationTableRow(compilation); compilationRowList.add(row); } Compilation selectedCompilation = selectedMember.getSelectedCompilation(); if (selectedCompilation != null) { compilationTable.getSelectionModel().clearAndSelect(selectedCompilation.getIndex()); } refreshOnce(); } public void setCompilationOnSelectedMember(IMetaMember member, int compilationIndex) { selectedProgrammatically = true; selectedMember = member; if (selectedMember != null) { selectedMember.setSelectedCompilation(compilationIndex); if (selectedMember.getSelectedCompilation() != null) { compilationTable.getSelectionModel().clearAndSelect(selectedMember.getSelectedCompilation().getIndex()); } focusTreeOnMember(selectedMember, true); } selectedProgrammatically = false; } private void refreshOnce() { if (codeCacheBlocksStage != null) { codeCacheBlocksStage.redraw(); } } private void refresh() { boolean sameVmCommandAsLastRun = sameVmCommand(); if (repaintTree) { repaintTree = false; classTree.showTree(sameVmCommandAsLastRun); } if (sameVmCommandAsLastRun) { if (lastSelectedMember != null) { focusTreeOnMember(lastSelectedMember, true); } else if (lastSelectedClass != null) { focusTreeOnClass(lastSelectedClass); } } if (timeLineStage != null) { timeLineStage.redraw(); } if (codeCacheTimelineStage != null) { codeCacheTimelineStage.redraw(); } if (statsStage != null) { statsStage.redraw(); } if (histoStage != null) { histoStage.redraw(); } if (topListStage != null) { topListStage.redraw(); } if (logBuffer.length() > 0) { refreshLog(); } long totalMemory = runtime.totalMemory(); long freeMemory = runtime.freeMemory(); long usedMemory = totalMemory - freeMemory; long megabyte = 1024 * 1024; String heapString = "Heap: " + (usedMemory / megabyte) + S_SLASH + (totalMemory / megabyte) + "M"; lblHeap.setText(heapString); btnErrorLog.setText("Errors (" + errorCount + S_CLOSE_PARENTHESES); } private void clearTextArea() { textAreaLog.clear(); } private void refreshLog() { textAreaLog.appendText(logBuffer.toString()); logBuffer.delete(0, logBuffer.length()); } public IMetaMember getSelectedMember() { return selectedMember; } void clearAndRefreshTreeView() { selectedMember = null; selectedMetaClass = null; classTree.clear(); classTree.showTree(sameVmCommand()); } @Override public void handleStageClosed(Stage stage) { if (stage instanceof TimeLineStage) { btnTimeLine.setDisable(false); timeLineStage = null; } else if (stage instanceof StatsStage) { btnStats.setDisable(false); statsStage = null; } else if (stage instanceof HistoStage) { btnHisto.setDisable(false); histoStage = null; } else if (stage instanceof MainConfigStage) { btnConfigure.setDisable(false); configStage = null; if (startDelayedByConfig) { readLogFile(); } } else if (stage instanceof TopListStage) { btnTopList.setDisable(false); topListStage = null; } else if (stage instanceof NothingMountedStage) { nothingMountedStage = null; if (configStage == null && startDelayedByConfig) { readLogFile(); } } else if (stage instanceof CodeCacheStage) { btnCodeCacheTimeline.setDisable(false); codeCacheTimelineStage = null; } else if (stage instanceof CodeCacheLayoutStage) { btnNMethods.setDisable(false); codeCacheBlocksStage = null; } else if (stage instanceof TriView) { btnTriView.setDisable(false); triViewStage = null; } else if (stage instanceof ReportStage) { switch (((ReportStage) stage).getType()) { case SUGGESTION: btnReportSuggestions.setDisable(false); reportStageSuggestions = null; break; case ELIMINATED_ALLOCATION: btnReportEliminatedAllocations.setDisable(false); reportStageElminatedAllocations = null; break; case ELIDED_LOCK: btnReportElidedLocks.setDisable(false); reportStageElidedLocks = null; break; case INLINING: break; } } else if (stage instanceof OptimizedVirtualCallStage) { btnOptimizedVirtualCalls.setDisable(false); ovcStage = null; } else if (stage instanceof BrowserStage) { browserStage = null; } else if (stage instanceof SandboxStage) { btnSandbox.setDisable(false); sandBoxStage = null; } } @Override public void handleJITEvent(JITEvent event) { log(event.toString()); repaintTree = true; } @Override public void handleLogEntry(String entry) { log(entry); } @Override public void handleErrorEntry(String entry) { errorLog.addEntry(entry); errorCount++; } private void log(final String entry) { logBuffer.append(entry); logBuffer.append(S_NEWLINE); } void metaClassSelectedFromClassTree(MetaClass metaClass) { classMemberList.clearClassMembers(); selectedMetaClass = metaClass; setSelectedMetaMember(null, true); if (metaClass == null) { // nothing selected return; } classMemberList.setMetaClass(metaClass); } public PackageManager getPackageManager() { return logParser.getModel().getPackageManager(); } @Override public Stage getStageForDialog() { return stage; } }